#pragma once
#include <iostream>
#include <string>
#include "Mutex.hpp"
#include <unistd.h>
#include <fstream>
#include <ctime>
#include <sstream>
#include<memory>
// zdl:: 这里需要借用c++17的标准
#include <filesystem>
// using namespace std;

//
namespace logMoudle
{
    using namespace LockModule;

    // zdl:: 获取当前的时间
    std::string getCurtime()
    {
        time_t time_stamp = ::time(nullptr);
        struct tm curr;
        localtime_r(&time_stamp, &curr);
        char buffer[1024];
        snprintf(buffer, sizeof(buffer), "%4d-%02d-%02d %02d:%02d;%02d",
                curr.tm_year, curr.tm_mon, curr.tm_mday, curr.tm_hour, curr.tm_min, curr.tm_sec);

        return buffer;
    }
    const std::string defaultPath = "./log";
    const std::string defaultFile = "log.txt";
    // zdl:: 日志等级
    enum class logLevel
    {
        debug = 1,
        info,
        warning,
        error,
        fatal
    };
    std::string level2String(logLevel &level)
    {
        switch (level)
        {
        case logLevel::debug:
            return "debug";
        case logLevel::info:
            return "info";
        case logLevel::warning:
            return "warning";
        case logLevel::error:
            return "error";
        case logLevel::fatal:
            return "fatal";
        }
        return "";
    }
    // zdl:: 刷新策略
    class logStrategy
    {
    public:
        virtual ~logStrategy() = default;
        virtual void syncLog(const std::string &message) = 0;
    };
    class consoleStrategy : public logStrategy
    {
    public:
        consoleStrategy()
        {
        }
        ~consoleStrategy()
        {
        }
        void synLog(const std::string &message)
        {
            LockGuard lockgaurd(_lock);
            std::cout << message << std::endl;
        }

    private:
        Mutex _lock;
    };

    // 文件策略
    class fileStrategy : public logStrategy
    {
    public:
        fileStrategy(const std::string &logpath = defaultPath,
                    const std::string &logname = defaultFile)
            : _logName(logname), _logPath(logpath)
        {
            if (std::filesystem::exists(_logPath))
                return;
            try
            {
                std::filesystem::create_directories(_logPath);
            }
            catch (std::filesystem::filesystem_error &e)
            {
                std::cerr << e.what() << std::endl;
            }
        }
        ~fileStrategy()
        {
        }
        void synLog(const std::string &message)
        {
            LockGuard lockgaurd(_lock);
            std::string log = _logPath + _logName;
            std::ofstream out(log, std::ios::app); // 日志写入
            if (!out.is_open())
            {
                return;
            }

            // 现在就是文件一定打开了
            out << message << std::endl;

            out.close();
        }

    private:
        std::string _logPath;
        std::string _logName;
        // zdl:: 锁，保证资源安全
        Mutex _lock;
    };

    // zdl:: 日志类: 构建i日志字符串
    class logger
    {

    public:
        logger()
        {
            // 默认采用consolelogstrategy的策略
            _strategy = std::make_shared<consoleStrategy>();
        }
        ~logger()
        {
        }
        void enableConsoleLogStrategy()
        {
            _strategy = std::make_shared<consoleStrategy>();
        }
        void enableFileLogstrategy()
        {
            _strategy = std::make_shared<fileStrategy>();
        }

        // zdl:: 一条完整的信息包含这样的信息： {2024- 3- 3 - 【【20234=】【debug] main .cc}
        class logMessage
        {
        private:
            std::string _curtime;  // 当前的日志时间
            logLevel _level;       // 日志等级
            pid_t _pid;            // 进程pid
            std::string _filename; // 日至=名称
            uint32_t _line;        // 日志所在的行号
            std::string _logInfo;  // 完整日志记录
            logger &_logger;       // 负责对不同的logger进行刷新
        public:
            logMessage(logLevel level, const std::string &filename,
                       int line, logger& logger)
                : _curtime(getCurtime()), _level(level), _pid(getpid()),
                  _filename(filename), _line(line), _logger(logger)
            {
                std::stringstream ssbuffer;
                ssbuffer << "[" << _curtime << "]" << "[" 
                << level2String(_level) << ']'
                << "[" << _pid << "]" <<"[" << _filename << "]" <<
                "[" << _line << "]" << std::endl;

                _logInfo = ssbuffer.str();
            }
            template<typename T>
            logMessage& operator<< (const T&info)
            {
                std::stringstream ss;
                ss << info;
                _logInfo += ss.str();
                return *this;
            }
            ~logMessage()
            {
                if (_logger._strategy)
                {
                    _logger._strategy->syncLog(_logInfo);
                }
            }
        };

        // 就是要拷贝
        logMessage operator()(logLevel level, const std::string &filename,
            int line)
        {
            return logMessage(level, filename, line, *this);
        }
    private:
        std::shared_ptr<logStrategy> _strategy;
    };

    logger lgr;

    #define log(level) lgr(level, __FILE__, __LINE__)

}